package isnork.g2;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import isnork.g2.utility.Utility;
import isnork.sim.BoardPanel;
import isnork.sim.GameObject;
import isnork.sim.Observation;
import isnork.sim.SeaLifePrototype;
import isnork.sim.GameObject.Direction;

public class Rout implements Strategy {
	Double expHappDensity;
	double x, y;
	double utility = Double.MAX_VALUE / 2;
	Point2D p;
	// private static final Point2D BOAT = new Point2D.Double(0.0, 0.0);
	int tick = 0;
	int finalTick = ExplorerConfig.FinalTick;
	double d;
	double r;
	double id;
	double n;
	double offset;
	boolean done = false;
	int i = 1;
	int lastTime;
	int timeNeed;

	public Rout(G2Explorer diver) {
		d = diver.d;
		r = diver.r;
		n = diver.n;
		id = Math.abs(diver.getId());
		offset = 4 * (2 * d - 2 * r) / (n * 0.8);
		if (id % 2 == 1) {
			i = -i;
		}
		
		if (id <= n * 0.2) {
			diver.toView.add(new Point2D.Double(d - r, d - r - offset * id));
			diver.toView.add(new Point2D.Double(d - r, -d + r));
			diver.toView.add(new Point2D.Double(-d + r, -d + r));
			diver.toView.add(new Point2D.Double(-d + r, d - r));
			diver.toView.add(new Point2D.Double(d - r, d - r));
			diver.toView.add(new Point2D.Double(d - r, d - r - offset * id));
			diver.toView.add(new Point2D.Double(d - 3*r, d - 3*r));
			diver.toView.add(new Point2D.Double(-d + 3*r, d - 3*r));
			diver.toView.add(new Point2D.Double(-d + 3*r, -d + 3*r));
			diver.toView.add(new Point2D.Double(d - 3*r, -d + 3*r));
		} else if (id <= n * 0.4) {
			diver.toView.add(new Point2D.Double(d - r - offset * (id - n *0.2),
					-d + r));
			diver.toView.add(new Point2D.Double(-d + r, -d + r));
			diver.toView.add(new Point2D.Double(-d + r, d - r));
			diver.toView.add(new Point2D.Double(d - r, d - r));
			diver.toView.add(new Point2D.Double(d - r, -d + r));
			diver.toView.add(new Point2D.Double(d - r - offset * (id - n *0.2),
					-d + r));
			diver.toView.add(new Point2D.Double(d - 3*r, -d + 3*r));
			diver.toView.add(new Point2D.Double(d - 3*r, d - 3*r));
			diver.toView.add(new Point2D.Double(-d + 3*r, d - 3*r));
			diver.toView.add(new Point2D.Double(-d + 3*r, -d + 3*r));
		} else if (id <= n * 0.6) {
			diver.toView.add(new Point2D.Double(-d + r, -d + r + offset
					* (id - n *0.4)));
			diver.toView.add(new Point2D.Double(-d + r, d - r));
			diver.toView.add(new Point2D.Double(d - r, d - r));
			diver.toView.add(new Point2D.Double(d - r, -d + r));
			diver.toView.add(new Point2D.Double(-d + r, -d + r));
			diver.toView.add(new Point2D.Double(-d + r, -d + r + offset
					* (id - n *0.4)));
			diver.toView.add(new Point2D.Double(-d + 3*r, -d + 3*r));
			diver.toView.add(new Point2D.Double(d - 3*r, -d + 3*r));
			diver.toView.add(new Point2D.Double(d - 3*r, d - 3*r));
			diver.toView.add(new Point2D.Double(-d + 3*r, d - 3*r));
			
		} else if (id <= n * 0.8) {
			diver.toView.add(new Point2D.Double(-d + r + offset
					* (id - n * 0.6), d - r));
			diver.toView.add(new Point2D.Double(d - r, d - r));
			diver.toView.add(new Point2D.Double(d - r, -d + r));
			diver.toView.add(new Point2D.Double(-d + r, -d + r));
			diver.toView.add(new Point2D.Double(-d + r, d - r));
			diver.toView.add(new Point2D.Double(-d + r + offset
					* (id - n * 0.6), d - r));
			diver.toView.add(new Point2D.Double(-d + 3*r, d - 3*r));
			diver.toView.add(new Point2D.Double(-d + 3*r, -d + 3*r));
			diver.toView.add(new Point2D.Double(d - 3*r, -d + 3*r));
			diver.toView.add(new Point2D.Double(d - 3*r, d - 3*r));
			
		} else {
			diver.toView.add(new Point2D.Double(i * (d - 3 * r), i
					* (d - 3 * r)));
			diver.toView.add(new Point2D.Double(-i * (d - 3 * r), i
					* (d - 3 * r)));
			diver.toView.add(new Point2D.Double(-i * (d - 3 * r), -i
					* (d - 3 * r)));
			diver.toView.add(new Point2D.Double(i * (d - 3 * r), -i
					* (d - 3 * r)));
			diver.toView.add(new Point2D.Double(i * (d - 3 * r), i
					* (d - 3 * r)));
			diver.toView.add(new Point2D.Double(-i * (d - 3 * r), i
					* (d - 3 * r)));
			diver.toView.add(new Point2D.Double(-i * (d - 3 * r), -i
					* (d - 3 * r)));
			diver.toView.add(new Point2D.Double(i * (d - 3 * r), -i
					* (d - 3 * r)));
			diver.toView.add(new Point2D.Double(-i*(d - r), -i*(d - r)));
			diver.toView.add(new Point2D.Double(i*(d - r), -i*(d - r)));
			diver.toView.add(new Point2D.Double(i*(d - r), i*(d - r)));
			diver.toView.add(new Point2D.Double(-i*(d - r), i*(d - r)));
			
		}
		if (diver.toView.isEmpty()) {
			done = true;
		} else
			diver.first = diver.toView.remove();

	}

	@Override
	public Map<Direction, Double> process(G2Explorer diver) {
		
		utility = diver.maxDanger*(diver.safeDegree-0.5)*0.3;

		Map<Direction, Double> utility_accumulatorExp = new HashMap<Direction, Double>();
		if (done){
			utility_accumulatorExp.put(Direction.STAYPUT, utility);
			//return utility_accumulatorExp;
			return null;
		
		}
			p = diver.first;
			
		Direction dir = Utility.RelativeDirection(diver.location, p);
		
		for(Direction d : Direction.values())
		{  
			if (d == dir)
			{
				utility_accumulatorExp.put(d, utility);
			}
			else if (Math.abs(d.getDegrees()-dir.getDegrees())==45)
			{
				utility_accumulatorExp.put(d, utility/1.1);
			}
			else if (Math.abs(d.getDegrees()-dir.getDegrees())==90)
			{
				utility_accumulatorExp.put(d, utility/1.3);
			}
		}
		if (p.distance(diver.location) < 2 || diver.current_round-lastTime>40) {
			if (diver.toView.isEmpty()) {
				done = true;
			} else{				
				Point2D tmp = diver.first;
				diver.first = diver.toView.remove();
				lastTime = diver.current_round;
			}
				
		}
		return utility_accumulatorExp;

	}
}